#include "msgbox.h"

#include "osCpu.h"

#if OS_ENABLE_MSGBOX == 1

/*****************************************************************************
 * @function        vMsgBoxInit
 * @brief 			消息邮箱初始化.
 *  
 * @param[in] 		msgbox 消息邮箱控制块.
 * @param[in]       msgBuffer 消息邮箱存储缓存区.
 * @param[in] 	    maxCount 最大消息数量.
 * 
 * @return 			None.	
 *
 * ***************************************************************************/
void vMsgBoxInit(MSG_BOX_T *msgbox, void **msgBuffer, uint32_t maxCount)
{
    vEventInit( &msgbox->event, eventTypeMsgBox);
    
    msgbox->msgBuffer = msgBuffer;          // 指定消息邮箱存储缓存区
    msgbox->maxCount = maxCount;            // 消息邮箱的最大消息缓存数    
    msgbox->read_idx = 0;                   // 读消息索引
    msgbox->write_idx = 0;                  // 写消息索引
    msgbox->count = 0;                      // 消息数量

}
    



/*****************************************************************************
 * @function        vMsgBoxSend
 * @brief 			向消息邮箱发送消息.
 *  
 * @param[in] 		msgbox  消息邮箱控制块.
 * @param[in]       msg     消息内容指针.
 * @param[in] 	    notifyPRI 是否有限发送消息. 1--优先发送，优先接收， 0-正常发送
 * 
 * @return 			发送结果： OS_NOERROR 发送成功.
 *                             OS_ERROR_NORESOURCE 发送失败，消息邮箱已满 
 *
 * ***************************************************************************/
uint32_t vMsgBoxSend(MSG_BOX_T *msgbox, void *msg, uint32_t notifyPRI)
{
    TASK_T *task;
    uint32_t primask = vTaskEnterCritical();
    
    /* 事件等待队列中存在任务*/
    if (vEventWaitCount( &msgbox->event))
    {
        task = vEventWakeUp(&msgbox->event, msg, OS_NOERROR);

        // 事件任务比当前任务优先级高
        if (task->prio < curTask->prio)
        {
            vTaskYield();
        }
    }
    /* 反之，消息放入存储区缓存*/
    else 
    {
        if (msgbox->count < msgbox->maxCount)
        {
            if (notifyPRI)
            {
                if (msgbox->read_idx == 0)
                {
                    msgbox->read_idx = msgbox->maxCount - 1;
                }
                else {
                    msgbox->read_idx --;
                }
                msgbox->msgBuffer[msgbox->read_idx] = msg;
            }
            else 
            {
                msgbox->msgBuffer[msgbox->write_idx++] = msg;
                msgbox->write_idx = msgbox->write_idx % msgbox->maxCount;
            }
            msgbox->count++;
        }
        /* 无资源*/
        else 
        {
            vTaskExitCritical(primask);
            return OS_ERROR_NORESOURCE;
        }
    }
    
    vTaskExitCritical(primask);
    return OS_NOERROR;
}



/*****************************************************************************
 * @function        vMsgBoxRecv
 * @brief 			接收消息邮箱中的消息
 *  
 * @param[in] 		msgbox  消息邮箱控制块.
 * @param[out]      msg     接收消息内容指针的指针.
 * @param[in] 	    timeout 等待消息的事件
 * 
 * @return 			接收结果： OS_NOERROR 接收成功.
 *
 * ***************************************************************************/
uint32_t vMsgBoxRecv(MSG_BOX_T *msgbox, void **msg, uint32_t timeout)
{
    uint32_t primask = vTaskEnterCritical();
    
    if (msgbox->count)
    {
        *msg = msgbox->msgBuffer[msgbox->read_idx++];
        msgbox->read_idx = msgbox->read_idx % msgbox->maxCount;
        msgbox->count--;    

        vTaskExitCritical(primask);
        return OS_NOERROR;
    }
    /* 消息邮箱中无消息，任务进入事件等待队列*/
    else 
    {
        vEventWait(&msgbox->event, curTask, (void *)0, OS_TASK_STA_WAIT_MSGBOX, timeout);
        vTaskExitCritical(primask);
        
        vTaskYield();
        /* i切换到该任务时，在此执行*/
        *msg = curTask->eventMsg;
        
        // 返回事件结果
        return curTask->waitEventResult;
    }
}



/*****************************************************************************
 * @function        vMsgBoxFlush
 * @brief 			清空消息邮箱。 将消息邮箱中的消息清空，count = 0;
 *  
 * @param[in] 		msgbox  待清空的消息邮箱.
 * 
 * @return 			None.
 *
 * ***************************************************************************/
void vMsgBoxFlush(MSG_BOX_T *msgbox)
{
    uint32_t primask = vTaskEnterCritical();
    
    if (vEventWaitCount(&msgbox->event) == 0)
    {
        msgbox->count = 0;
        msgbox->read_idx = 0;
        msgbox->write_idx = 0;
    }
    
    vTaskExitCritical(primask);
}



/*****************************************************************************
 * @function        vMsgBoxDestroy
 * @brief 			销毁消息邮箱。 将消息邮箱中的事件等待任务释放，任务进入就绪队列。
 *  
 * @param[in] 		msgbox  待销毁的消息邮箱.
 * 
 * @return 			被释放的任务数量.
 *
 * ***************************************************************************/
uint32_t vMsgBoxDestroy(MSG_BOX_T *msgbox)
{
    uint32_t count = 0;
    uint32_t primask = vTaskEnterCritical();
    
    count = vEventRemoveAll(&msgbox->event, (void *)0, OS_FORCE_DEL);
    
    vTaskExitCritical(primask);
    
    if (count > 0)
    {
        vTaskYield();
    }
    
    return count;
}


/*****************************************************************************
 * @function        vMsgBoxGetInfo
 * @brief 			获取邮箱队列相关信息。
 *  
 * @param[in] 		msgbox  待查询的消息邮箱.
 * @param[out]      info    消息邮箱信息控制块
 * 
 * @return 			None.
 *
 * ***************************************************************************/
void vMsgBoxGetInfo(MSG_BOX_T *msgbox, MSG_BOX_INFO_T *info)
{
    uint32_t primask = vTaskEnterCritical();
    
    info->count = msgbox->count;
    info->maxCount = msgbox->maxCount;
    info->taskCount = vEventWaitCount(&msgbox->event);
    
    vTaskExitCritical(primask);
}

#endif // OS_ENABLE_MSGBOX == 1
